package zsy.test.java.util.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author zhangshuaiyin
 * @date 2022/4/2 11:22
 */
public class ThreadSleepDemo {
    private static final Logger log = LoggerFactory.getLogger(ThreadSleepDemo.class);

    /**
     * 执行标识，true-执行中 false-睡眠状态
     */
    private final AtomicBoolean signal = new AtomicBoolean();

    /**
     * 执行线程
     */
    private final Thread thread;

    /**
     * 程序运行标识 true-正在运行 false-停止状态
     */
    private boolean runnable;

    /**
     * 对外开放调用内部业务逻辑接口，在业务代码中调用该方法实现业务逻辑的执行；
     * <p>
     * 避免每次调用该方法都会执行业务逻辑，适合业务逻辑IO频繁，保证最终一致性，如清空缓存等。
     */
    public void publicBusiness() {
        log.info("对外业务逻辑调用方法，控制并发执行频率");
        signal.compareAndSet(false, true);
    }

    /**
     * 内部执行业务逻辑接口
     */
    private void doBusiness() {
        while (runnable) {
            if (signal.get()) {
                log.info("ThreadSleepDemo --> 执行业务逻辑开始");
                try {
                    // 业务逻辑
                    log.info("执行真正业务逻辑");
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    signal.set(false);
                }
                log.info("ThreadSleepDemo --> 执行业务逻辑结束");
            }
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException ignore) {
            }
        }
    }

    public ThreadSleepDemo() {
        // Spring框架可以使用 InitializingBean 接口的 afterPropertiesSet() 方法
        this.runnable = true;
        this.thread = new Thread(this::doBusiness);
        this.thread.setDaemon(true);
        this.thread.start();
    }

    @Override
    protected void finalize() throws Throwable {
        // Spring框架可以使用 DisposableBean 接口的 destroy() 方法
        super.finalize();
        this.runnable = false;
        if (thread != null) {
            thread.interrupt();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadSleepDemo demo = new ThreadSleepDemo();
        for (int i = 0; i < 10; i++) {
            demo.publicBusiness();
        }
        TimeUnit.DAYS.sleep(1);
    }
}
